namespace Digitalmes.Application.Mes;

/// <summary>
/// 生产工单排程服务接口
/// </summary>
[ApiExplorerSettings(GroupName = "mes")]
public sealed class ProdWoScheduleService : IDynamicWebApiService 
{
    private readonly SugarRepository<ProdWoSchedule> _scheduleRepo;
    private readonly SugarRepository<ProdWo> _woRepo;

    public ProdWoScheduleService(SugarRepository<ProdWoSchedule> scheduleRepo, SugarRepository<ProdWo> woRepo)
    {
        _scheduleRepo = scheduleRepo;
        _woRepo = woRepo;
    }

    /// <summary>
    /// 获取待排产的工单
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<PageResult<ProdWoDto>> GetToDoPagesAsync(PageParam param)
    {
        // 获取状态为 "已创建" 的工单 
        var query = await _woRepo.AsQueryable()
            .Includes(s => s.Product)
            .Where(s => s.Status == WoStatusEnum.Created)
            .ToPageAsync(param.Page, param.Limit);
        return query.Adapt<PageResult<ProdWoDto>>();
    }

    /// <summary>
    /// 获取已排产的工单
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<PageResult<ProdWoScheduleDto>> GetDonePagesAsync(PageParam param)
    {
        // 获取状态为 ["已排产", "已下发", "生产中", "已暂停"] 的工单 
        WoStatusEnum[] statuses = { WoStatusEnum.Scheduled, WoStatusEnum.Issued, WoStatusEnum.Executing, WoStatusEnum.Paused };
        var query = await _scheduleRepo.AsQueryable()
            .Includes(s => s.WorkOrder, t => t!.Product)
            .Where(s => statuses.Contains(s.WorkOrder!.Status))
            .OrderByDescending(s => s.Sort)
            .ToPageAsync(param.Page, param.Limit);
        return query.Adapt<PageResult<ProdWoScheduleDto>>();
    }

    /// <summary>
    /// 排产
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<bool> ScheduleAsync(List<ProdWoScheduleParam> models)
    {
        // 仅工单处于 "已创建" 状态才能进行排产
        var ids = models.Select(s => s.WoId).ToArray();
        var items = await _woRepo.GetListAsync(s => ids.Contains(s.Id) && s.Status == WoStatusEnum.Created);
        if (!items.Any())
        {
            return true;
        }

        // 排序号累加
        var maxSort = await _scheduleRepo.AsQueryable().MaxAsync(s => s.Sort);

        // 添加排产项
        var lineId = models.First().LineId;
        var lineCode = models.First().LineCode;
        var schedules = items.Select(s => new ProdWoSchedule
        {
            WoId = s.Id,
            Wo = s.Wo,
            LineId = lineId,
            LineCode = lineCode,
            Sort = ++maxSort,
        }).ToArray();
        await _scheduleRepo.InsertRangeAsync(schedules);

        // 设置工单为 "已排产" 状态
        items.ForEach(s =>
        {
            s.SetStatus(WoStatusEnum.Scheduled);
        });

        return await _woRepo.UpdateAsync(items, s => new { s.Status, s.LastStatus, s.UpdateTime, s.UpdateUser });
    }

    /// <summary>
    /// 取消排产
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<bool> UnScheduleAsync(List<ProdWoScheduleDto> models)
    {
        // 校验工单状态，只有处于 "已排产" 状态的工单才能取消排产
        var ids = models.Select(s => s.WoId).ToArray();
        var items = await _woRepo.GetListAsync(s => ids.Contains(s.Id) && s.Status == WoStatusEnum.Scheduled);
        if (!items.Any())
        {
            return true;
        }

        // 删除排产项
        var scheduleIds = models
            .Where(s => items.Any(t => t.Id == s.WoId))
            .Select(s => s.Id)
            .ToArray();
        await _scheduleRepo.AsDeleteable().Where(s => scheduleIds.Contains(s.Id)).ExecuteCommandAsync();

        // 设置工单为 "已创建" 状态
        items.ForEach(s =>
        {
            s.SetStatus(WoStatusEnum.Created);
        });

        return await _woRepo.UpdateAsync(items, s => new { s.Status, s.LastStatus, s.UpdateTime, s.UpdateUser });
    }

    [HttpPut]
    public async Task SortAsync(ProdWoScheduleSortParam param)
    {
        var source = await _scheduleRepo.GetByIdAsync(param.SourceId);
        var target = await _scheduleRepo.GetByIdAsync(param.TargetId);

        (source.Sort, target.Sort) = (target.Sort, source.Sort);
        await _scheduleRepo
           .AsUpdateable(new ProdWoSchedule[] { source, target })
           .UpdateColumns(s => new { s.Sort, s.UpdateTime, s.UpdateUser })
           .ExecuteCommandAsync();
    }
}
